package com.cms.jy.utils;

import okhttp3.*;

import javax.net.ssl.*;
import java.io.IOException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * OkHttp 工具类
 */
public class OkHttpUtils {

    private static final MediaType JSON = MediaType.get("application/json; charset=utf-8");

    private final OkHttpClient client;
    private final OkHttpClient unsafeClient;

    public OkHttpUtils() {
        this.client = new OkHttpClient.Builder()
                .connectTimeout(120, TimeUnit.SECONDS)
                .writeTimeout(120, TimeUnit.SECONDS)
                .readTimeout(600, TimeUnit.SECONDS)
                .retryOnConnectionFailure(true)
                .build();

        // 创建一个忽略SSL证书验证的client
        this.unsafeClient = createUnsafeClient();
    }

    /**
     * 创建忽略SSL证书验证的OkHttpClient
     * @return OkHttpClient
     */
    private OkHttpClient createUnsafeClient() {
        try {
            final TrustManager[] trustAllCerts = new TrustManager[]{
                    new X509TrustManager() {
                        @Override
                        public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
                        }

                        @Override
                        public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
                        }

                        @Override
                        public X509Certificate[] getAcceptedIssuers() {
                            return new X509Certificate[]{};
                        }
                    }
            };

            final SSLContext sslContext = SSLContext.getInstance("SSL");
            sslContext.init(null, trustAllCerts, new java.security.SecureRandom());
            final SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();

            return new OkHttpClient.Builder()
                    .sslSocketFactory(sslSocketFactory, (X509TrustManager) trustAllCerts[0])
                    .hostnameVerifier(new HostnameVerifier() {
                        @Override
                        public boolean verify(String hostname, SSLSession session) {
                            return true;
                        }
                    })
                    .connectTimeout(120, TimeUnit.SECONDS)
                    .writeTimeout(120, TimeUnit.SECONDS)
                    .readTimeout(120, TimeUnit.SECONDS)
                    .build();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 发送 GET 请求
     *
     * @param url     请求地址
     * @param headers 请求头（可选）
     * @return 响应内容
     * @throws IOException IO异常
     */
    public String get(String url, Map<String, String> headers) throws IOException {
        return get(url, headers, false);
    }

    /**
     * 发送 GET 请求
     *
     * @param url     请求地址
     * @param headers 请求头（可选）
     * @param unsafe  是否忽略SSL证书验证
     * @return 响应内容
     * @throws IOException IO异常
     */
    public String get(String url, Map<String, String> headers, boolean unsafe) throws IOException {
        Request.Builder builder = new Request.Builder().url(url);

        if (headers != null && !headers.isEmpty()) {
            for (Map.Entry<String, String> entry : headers.entrySet()) {
                builder.addHeader(entry.getKey(), entry.getValue());
            }
        }

        Request request = builder.build();
        OkHttpClient clientToUse = unsafe ? unsafeClient : client;
        try (Response response = clientToUse.newCall(request).execute()) {
            if (!response.isSuccessful()) {
                throw new IOException("Unexpected code " + response);
            }
            ResponseBody body = response.body();
            return body != null ? body.string() : null;
        }
    }

    /**
     * 发送 POST 请求（JSON 格式数据）
     *
     * @param url      请求地址
     * @param json     JSON 数据
     * @param headers  请求头（可选）
     * @return 响应内容
     * @throws IOException IO异常
     */
    public String postJson(String url, String json, Map<String, String> headers) throws IOException {
        return postJson(url, json, headers, false);
    }

    /**
     * 发送 POST 请求（JSON 格式数据）
     *
     * @param url      请求地址
     * @param json     JSON 数据
     * @param headers  请求头（可选）
     * @param unsafe   是否忽略SSL证书验证
     * @return 响应内容
     * @throws IOException IO异常
     */
    public String postJson(String url, String json, Map<String, String> headers, boolean unsafe) throws IOException {
        RequestBody body = RequestBody.create(json, JSON);
        Request.Builder builder = new Request.Builder()
                .url(url)
                .post(body);

        if (headers != null && !headers.isEmpty()) {
            for (Map.Entry<String, String> entry : headers.entrySet()) {
                builder.addHeader(entry.getKey(), entry.getValue());
            }
        }

        Request request = builder.build();
        OkHttpClient clientToUse = unsafe ? unsafeClient : client;
        try (Response response = clientToUse.newCall(request).execute()) {
            if (!response.isSuccessful()) {
                throw new IOException("Unexpected code " + response);
            }
            ResponseBody responseBody = response.body();
            return responseBody != null ? responseBody.string() : null;
        }
    }

    /**
     * 发送 PUT 请求（JSON 格式数据）
     *
     * @param url      请求地址
     * @param json     JSON 数据
     * @param headers  请求头（可选）
     * @return 响应内容
     * @throws IOException IO异常
     */
    public String putJson(String url, String json, Map<String, String> headers) throws IOException {
        return putJson(url, json, headers, false);
    }

    /**
     * 发送 PUT 请求（JSON 格式数据）
     *
     * @param url      请求地址
     * @param json     JSON 数据
     * @param headers  请求头（可选）
     * @param unsafe   是否忽略SSL证书验证
     * @return 响应内容
     * @throws IOException IO异常
     */
    public String putJson(String url, String json, Map<String, String> headers, boolean unsafe) throws IOException {
        RequestBody body = RequestBody.create(json, JSON);
        Request.Builder builder = new Request.Builder()
                .url(url)
                .put(body);

        if (headers != null && !headers.isEmpty()) {
            for (Map.Entry<String, String> entry : headers.entrySet()) {
                builder.addHeader(entry.getKey(), entry.getValue());
            }
        }

        Request request = builder.build();
        OkHttpClient clientToUse = unsafe ? unsafeClient : client;
        try (Response response = clientToUse.newCall(request).execute()) {
            if (!response.isSuccessful()) {
                throw new IOException("Unexpected code " + response);
            }
            ResponseBody responseBody = response.body();
            return responseBody != null ? responseBody.string() : null;
        }
    }

    /**
     * 发送 DELETE 请求
     *
     * @param url     请求地址
     * @param headers 请求头（可选）
     * @return 响应内容
     * @throws IOException IO异常
     */
    public String delete(String url, Map<String, String> headers) throws IOException {
        return delete(url, headers, false);
    }

    /**
     * 发送 DELETE 请求
     *
     * @param url     请求地址
     * @param headers 请求头（可选）
     * @param unsafe  是否忽略SSL证书验证
     * @return 响应内容
     * @throws IOException IO异常
     */
    public String delete(String url, Map<String, String> headers, boolean unsafe) throws IOException {
        Request.Builder builder = new Request.Builder()
                .url(url)
                .delete();

        if (headers != null && !headers.isEmpty()) {
            for (Map.Entry<String, String> entry : headers.entrySet()) {
                builder.addHeader(entry.getKey(), entry.getValue());
            }
        }

        Request request = builder.build();
        OkHttpClient clientToUse = unsafe ? unsafeClient : client;
        try (Response response = clientToUse.newCall(request).execute()) {
            if (!response.isSuccessful()) {
                throw new IOException("Unexpected code " + response);
            }
            ResponseBody responseBody = response.body();
            return responseBody != null ? responseBody.string() : null;
        }
    }

    public byte[] postJsonForBytes(String url, String jsonBody, Map<String, String> headers, boolean enableLog) throws Exception {
        OkHttpClient client = new OkHttpClient();
        RequestBody requestBody = RequestBody.create(jsonBody, MediaType.parse("application/json; charset=utf-8"));

        Request.Builder builder = new Request.Builder().url(url);
        if (headers != null) {
            for (Map.Entry<String, String> entry : headers.entrySet()) {
                builder.addHeader(entry.getKey(), entry.getValue());
            }
        }
        builder.post(requestBody);

        try (Response response = client.newCall(builder.build()).execute()) {
            if (!response.isSuccessful()) throw new IOException("Unexpected code " + response);
            if (response.body() == null) throw new IOException("Empty response body");
            return response.body().bytes();
        }
    }

}
